﻿#pragma once
// Inner Fire 游戏引擎库
// GPU波浪
//
// Copyright (c) 2023 by 尔西大帝. All rights reserved.
//
// GPU波浪的工具类。根据《DirectX12游戏开发实战》中的工具类修改。
// 原作者：Frank Luna
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2024-11-26

#include <dx_core/dx_core.h>
#include <vector>

namespace ifire {

class GpuWaves {
public:
  // Note that m,n should be divisible by 16 so there is no
  // remainder when we divide into thread groups.
  GpuWaves(ID3D12Device* device, ID3D12GraphicsCommandList* cmdList, int m,
      int n, float dx, float dt, float speed, float damping);
  GpuWaves(const GpuWaves& rhs) = delete;
  GpuWaves& operator=(const GpuWaves& rhs) = delete;
  ~GpuWaves() = default;

  UINT RowCount() const;
  UINT ColumnCount() const;
  UINT VertexCount() const;
  UINT TriangleCount() const;
  float Width() const;
  float Depth() const;
  float SpatialStep() const;

  CD3DX12_GPU_DESCRIPTOR_HANDLE DisplacementMap() const;

  UINT DescriptorCount() const;

  void BuildResources(ID3D12GraphicsCommandList* cmdList);

  void BuildDescriptors(CD3DX12_CPU_DESCRIPTOR_HANDLE hCpuDescriptor,
      CD3DX12_GPU_DESCRIPTOR_HANDLE hGpuDescriptor, UINT descriptorSize);

  void Update(ID3D12GraphicsCommandList* cmdList, ID3D12RootSignature* rootSig,
      ID3D12PipelineState* pso);

  void Disturb(ID3D12GraphicsCommandList* cmdList, ID3D12RootSignature* rootSig,
      ID3D12PipelineState* pso, UINT i, UINT j, float magnitude);

  void SetToRead(ID3D12GraphicsCommandList* cmdList, ID3D12Resource* res);
  void SetToAccess(ID3D12GraphicsCommandList* cmdList, ID3D12Resource* res);
  void SetAllRead(ID3D12GraphicsCommandList* cmdList);
  void SetAllAccess(ID3D12GraphicsCommandList* cmdList);

private:
  UINT mNumRows;
  UINT mNumCols;

  UINT mVertexCount;
  UINT mTriangleCount;

  // Simulation constants we can precompute.
  float mK[3];

  float mTimeStep;
  float mSpatialStep;

  ID3D12Device* md3dDevice = nullptr;

  CD3DX12_GPU_DESCRIPTOR_HANDLE mPrevSolSrv;
  CD3DX12_GPU_DESCRIPTOR_HANDLE mCurrSolSrv;
  CD3DX12_GPU_DESCRIPTOR_HANDLE mNextSolSrv;

  CD3DX12_GPU_DESCRIPTOR_HANDLE mPrevSolUav;
  CD3DX12_GPU_DESCRIPTOR_HANDLE mCurrSolUav;
  CD3DX12_GPU_DESCRIPTOR_HANDLE mNextSolUav;

  // Two for ping-ponging the textures.
  Microsoft::WRL::ComPtr<ID3D12Resource> prev_ = nullptr;
  Microsoft::WRL::ComPtr<ID3D12Resource> curr_ = nullptr;
  Microsoft::WRL::ComPtr<ID3D12Resource> next_ = nullptr;

  Microsoft::WRL::ComPtr<ID3D12Resource> mPrevUploadBuffer = nullptr;
  Microsoft::WRL::ComPtr<ID3D12Resource> mCurrUploadBuffer = nullptr;
};

} // namespace ifire
